<!-- 代码编辑器 -->
<template>
  <div class="editor">
    <div v-if="isDarkMode" class="tools">
      <div class="tools-btn-box">
        <span> 深色模式 </span>
        <a-switch v-model:checked="editorOptions.theme" checked-value="vs-dark" un-checked-value="vs" size="small" />
      </div>
    </div>
    <div class="code-edit-box"></div>
  </div>
</template>

<script lang="ts" setup>
  import * as monaco from 'monaco-editor'
  import { nextTick, onBeforeUnmount, reactive, ref, watch } from 'vue'

  interface EditorOptions {
    theme: 'vs' | 'vs-dark' //主题色
  }

  export interface Props {
    value?: string // 文本值
    isDarkTheme?: boolean // 是否深色模式
    isDarkMode?: boolean // 是否需要深色模式
  }

  const props = withDefaults(defineProps<Props>(), {
    value: '',
    isDarkTheme: false,
    isDarkMode: true
  })

  const emits = defineEmits<{
    (e: 'update:isDarkTheme', params: boolean): void
    (e: 'update:value', params: string): void
  }>()

  const text = ref(``)

  self.MonacoEnvironment = {
    getWorker: function (workerId: string, label: string) {
      // @ts-ignore
      const getWorkerModule = (moduleUrl, label) => {
        // @ts-ignore
        return new Worker(self.MonacoEnvironment.getWorkerUrl(moduleUrl), {
          name: label,
          type: 'module'
        })
      }

      switch (label) {
        case 'json':
          return getWorkerModule('/monaco-editor/esm/vs/language/json/json.worker?worker', label)
        case 'css':
        case 'scss':
        case 'less':
          return getWorkerModule('/monaco-editor/esm/vs/language/css/css.worker?worker', label)
        case 'html':
        case 'handlebars':
        case 'razor':
          return getWorkerModule('/monaco-editor/esm/vs/language/html/html.worker?worker', label)
        case 'typescript':
        case 'javascript':
          return getWorkerModule('/monaco-editor/esm/vs/language/typescript/ts.worker?worker', label)
        default:
          return getWorkerModule('/monaco-editor/esm/vs/editor/editor.worker?worker', label)
      }
    }
  }

  let editor: monaco.editor.IStandaloneCodeEditor
  let codeEditBox: HTMLElement

  const editorOptions = reactive<EditorOptions>({
    theme: props.isDarkTheme ? 'vs-dark' : 'vs'
  })

  // 动态修改宽高的函数
  function setEditorSize(layout: { width?: number; height?: number }) {
    console.log(layout)
    layout.width && (codeEditBox.style.width = layout.width + 'px')
    layout.height && (codeEditBox.style.height = layout.height + 'px')
  }

  // 监听主题切换
  watch(
    () => editorOptions.theme,
    val => {
      emits('update:isDarkTheme', val === 'vs-dark')
      monaco.editor.setTheme(val)
    } //设置主题
  )

  // 初始化编辑器
  const editorInit = () => {
    nextTick(() => {
      monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
        noSemanticValidation: true,
        noSyntaxValidation: false
      })
      monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
        target: monaco.languages.typescript.ScriptTarget.ES2016,
        allowNonTsExtensions: true
      })

      codeEditBox = document.querySelector('.code-edit-box') as HTMLElement

      !editor
        ? (editor = monaco.editor.create(codeEditBox, {
            value: props.value, // 编辑器初始显示文字
            language: 'python', // 语言支持自行查阅demo
            automaticLayout: true, // 自适应布局
            theme: editorOptions.theme, // 官方自带三种主题vs, hc-black, or vs-dark
            foldingStrategy: 'indentation', // 代码可分小段折叠
            renderLineHighlight: 'all', // 行亮
            selectOnLineNumbers: true, // 显示行号
            minimap: {
              enabled: false
            },
            readOnly: false, // 只读
            fontSize: 16, // 字体大小
            scrollBeyondLastLine: false, // 取消代码后面一大段空白
            overviewRulerBorder: false, // 不要滚动条的边框
            wordWrap: 'on', // 自动换行
            tabSize: 2 // tab 缩进长度
          }))
        : editor.setValue('')

      // 监听值的变化
      editor.onDidChangeModelContent(() => {
        text.value = editor.getValue()
        emits('update:value', text.value)
      })
    })
  }

  // 设置语言
  const setLanguage = (language: string) => {
    const textModal = editor.getModel()
    if (textModal === null) {
      console.warn('请先初始化编辑器')
      return
    }
    monaco.editor.setModelLanguage(textModal, language)
  }

  const setValue = (val: string) => {
    editor.setValue(val)
  }

  // 禁用/启用 编辑器
  const setReadOnly = (bool: boolean) => {
    editor.updateOptions({
      readOnly: bool
    })
  }

  editorInit()

  onBeforeUnmount(() => {
    editor.dispose() //销毁实例
  })

  defineExpose({
    setLanguage,
    setReadOnly,
    setValue,
    setEditorSize
  })

  // 常用设置
  // editor.setValue('77777')
  // editor.getValue()
  // editor.dispose() //销毁实例
  // monaco.editor.setModelLanguage(editor.getModel(), 'javascript') //语言设置
  // editor.getAction('editor.action.formatDocument').run() //格式化代码
  // 监听事件
  // editor.onDidChangeModelContent((val)=>{ //监听值的变化  })
  // editor.onDidChangeOptions //配置改变事件
  // editor.onDidChangeLanguage //语言改变事件
  // monaco.editor.setTheme(newTheme) //设置主题
  // editor.updateOptions({ readOnly: true }) //修改配置
</script>

<style lang="less" scoped>
  .editor {
    display: flex;
    flex-direction: column;

    .tools {
      display: flex;
      justify-content: flex-end;
      align-items: center;
      padding: 4px 24px;
      height: 24px;
      border-bottom: 1px solid @border3;

      .tools-btn-box {
        display: flex;
        justify-content: space-between;
        align-items: center;
        width: 96px;
      }
    }

    .code-edit-box {
      height: 100%;
    }
  }
</style>
